home *** CD-ROM | disk | FTP | other *** search
/ TOS Silver 2000 / TOS Silver 2000.iso / Spiele / GEMSPIEL / COLTRIS / SOURCES / TETRIS.C < prev   
Encoding:
C/C++ Source or Header  |  1995-01-27  |  9.7 KB  |  467 lines

  1. #include "cltr.h"
  2.  
  3. void dr_vdi(int x,int y,int col,int x_off,int y_off);
  4.  
  5. extern GAME *game;
  6.  
  7. /*
  8.     assembler routine zum kopieren eines blockes in den puffer
  9. */
  10. #define WIDTH        10                /* breite des spielfeldes in blöcken */
  11. #define HEIGHT        20                /* höhe */
  12.     /* FIRSTCOLUMN=1, hardcoded */
  13. #define FIRSTLINE    4                /* erste angezeigte zeile */
  14. #define XWIDTH        (WIDTH+2)        /* breite des internen feldes */
  15. #define XHEIGHT        (HEIGHT+FIRSTLINE+1)    /* höhe */
  16.  
  17. static int feld[XHEIGHT][XWIDTH];
  18.  
  19. void tetris_preview(void);
  20. void dr_tstat(int x,int y,int dy);
  21. uint do_tetris(void);
  22.  
  23. GAME tetris={
  24.     "Tetris",
  25.     tetris_preview,
  26.     dr_tstat,
  27.     do_tetris,
  28.     WIDTH,
  29.     HEIGHT,
  30.     FIRSTLINE,
  31.     5,
  32.     5
  33. };
  34.  
  35. /*
  36.     beschreibung der spielsteine für ausgabe
  37. */
  38. typedef struct {    /* relative positions-offsets (in blöcken) */
  39.     int x[4];
  40.     int y[4];
  41. } DIR;
  42. typedef struct {
  43.     int dirs;        /* zahl möglicher orientierungen */
  44.     DIR dir[4];
  45. } STONES;
  46.  
  47. /*
  48. unused    XXXX     XXX    XXX        XXX        XX         XX        XX
  49.                    X    X         X         XX        XX        XX
  50. */
  51. static STONES tet[]={
  52.     {    0,{{{0,0,0,0},{0,0,0,0}},{{0,0,0,0},{0,0,0,0}},{{0,0,0,0},{0,0,0,0}},{{0,0,0,0},{0,0,0,0}}} },
  53.     {    2,{{{-2,-1,0,1},{0,0,0,0}},{{0,0,0,0},{-2,-1,0,1}},{{0,0,0,0},{0,0,0,0}},{{0,0,0,0},{0,0,0,0}}} },
  54.     {    4,{{{-1,0,1,1},{0,0,0,1}},{{1,0,0,0},{-1,-1,0,1}},{{-1,-1,0,1},{-1,0,0,0}},{{0,0,0,-1},{-1,0,1,1}}} },
  55.     {    4,{{{-1,0,1,1},{0,0,0,-1}},{{-1,0,0,0},{-1,-1,0,1}},{{-1,-1,0,1},{1,0,0,0}},{{0,0,0,1},{-1,0,1,1}}} },
  56.     {    4,{{{-1,0,0,1},{0,0,1,0}},{{0,0,1,0},{-1,0,0,1}},{{-1,0,0,1},{0,0,-1,0}},{{0,0,-1,0},{-1,0,0,1}}} },
  57.     {    2,{{{-1,0,0,1},{1,1,0,0}},{{0,0,1,1},{-1,0,0,1}},{{0,0,0,0},{0,0,0,0}},{{0,0,0,0},{0,0,0,0}}} },
  58.     {    2,{{{-1,0,0,1},{0,0,1,1}},{{1,1,0,0},{-1,0,0,1}},{{0,0,0,0},{0,0,0,0}},{{0,0,0,0},{0,0,0,0}}} },
  59.     {    1,{{{0,1,0,1},{0,0,1,1}},{{0,0,0,0},{0,0,0,0}},{{0,0,0,0},{0,0,0,0}},{{0,0,0,0},{0,0,0,0}}}    }
  60. };
  61.  
  62. /*
  63.     beschreibung eines steines
  64. */
  65. typedef struct {
  66.     int x;
  67.     int y;
  68.     int typ;
  69.     int dir;
  70. } STONE;
  71.  
  72. static STONE stone,next;
  73.  
  74. /*
  75.     lösche stein in puffer
  76. */
  77. static void rm_stone(void)
  78. {
  79. int i,y;
  80.  
  81.     for ( i=0; i<4; i++ ) {
  82.         y=stone.y+tet[stone.typ].dir[stone.dir].y[i];
  83.         if ( y>=FIRSTLINE ) {
  84.             tetris.dr_block(stone.x+tet[stone.typ].dir[stone.dir].x[i],y,0);
  85.         }
  86.     }
  87. }
  88.  
  89. /*
  90.     zeichne stein in puffer
  91. */
  92. static void dr_stone(void)
  93. {
  94. int i,y;
  95. DIR *dir;
  96.  
  97.     dir=&tet[stone.typ].dir[stone.dir];
  98.  
  99.     for ( i=0; i<4; i++ ) {
  100.         y=stone.y+dir->y[i];
  101.         if ( y>=FIRSTLINE ) {
  102.             tetris.dr_block(stone.x+dir->x[i],y,stone.typ);
  103.         }
  104.     }
  105. }
  106.  
  107. /*------------------------------------------------------------------------------
  108.  
  109.     preview
  110.  
  111. ------------------------------------------------------------------------------*/
  112. #define PREV_X    3
  113. #define PREV_Y    FIRSTLINE+2
  114.  
  115. void tetris_preview(void)
  116. {
  117. int i;
  118. DIR *dir=&tet[next.typ].dir[next.dir];
  119.  
  120.     for ( i=0; i<4; i++ )
  121.         dr_vdi(PREV_X+dir->x[i],PREV_Y+dir->y[i],next.typ,prev_x+(prev_w-tetris.block_w*4)/2,prev_y+(prev_h-tetris.block_h*4)/2);
  122. }
  123.  
  124. /*------------------------------------------------------------------------------
  125.  
  126.     statistik
  127.  
  128. ------------------------------------------------------------------------------*/
  129. void dr_tstat(int x,int y,int dy)
  130. {
  131. int i;
  132.     y+=dy/2;
  133.     x-=tetris.block_w*2;
  134.     for ( i=1; i<8; i++,y+=dy )
  135.         dr_vdi(2,FIRSTLINE,i,x,y );
  136. }
  137.  
  138. /*------------------------------------------------------------------------------
  139.  
  140.     spiel initialisieren
  141.  
  142. ------------------------------------------------------------------------------*/
  143. static void init_feld(void)
  144. {
  145. int i,j;
  146.  
  147.     for ( i=0; i<XHEIGHT; i++ ) {
  148.         for ( j=0; j<XWIDTH; j++ )
  149.             feld[i][j]=0;
  150.         feld[i][0]=feld[i][XWIDTH-1]=-1;
  151.     }
  152.     for ( j=0; j<XWIDTH; j++ )
  153.         feld[XHEIGHT-1][j]=-1;
  154.  
  155.     for ( i=XHEIGHT-1-opts.opts[PM_TETRIS].random; i<XHEIGHT-1; i++ ) {
  156.         for ( j=1; j<XWIDTH-1; j++ ) {
  157.             feld[i][j]=(int)(xrandom()%14+1);
  158.             if ( feld[i][j]>7 )
  159.                 feld[i][j]=0;
  160.             else
  161.                 tetris.dr_block(j,i,feld[i][j]);
  162.         }
  163.     }
  164.     copy_out();
  165. }
  166.  
  167. /*
  168.     erzeuge neuen stein
  169. */
  170. static void init_stone(void)
  171. {
  172.     next.x=XWIDTH/2;
  173.     next.y=2;
  174.     next.typ=(int)(xrandom()%7+1);
  175.     next.dir=(int)(xrandom()%tet[next.typ].dirs);
  176. }
  177.  
  178. /*------------------------------------------------------------------------------
  179.  
  180.     position der steine testen
  181.         COLUMNS != TETRIS 
  182.     tetris: mache kopie des akt. steines mit neuer pos.
  183.             teste neue pos
  184. ------------------------------------------------------------------------------*/
  185. /*
  186.     teste ob stein 'stone' an die angeg. pos darf
  187. */
  188. static int check_pos(STONE *stone)
  189. {
  190. int i;
  191. DIR *dir;
  192.  
  193.     dir=&tet[stone->typ].dir[stone->dir];
  194.     for ( i=0; i<4; i++ ) {
  195.         if ( feld[stone->y+dir->y[i]][stone->x+dir->x[i]]!=0 )
  196.             return 1;
  197.     }
  198.     return 0;
  199. }
  200. /*
  201.     teste ob nichtsichbarer oberer rand leer
  202.         falls nicht -> game over
  203. */
  204. static int xcheck(void)
  205. {
  206. int i,j;
  207.  
  208.     for ( i=0; i<FIRSTLINE; i++ )
  209.         for ( j=1; j<XWIDTH-1; j++ )
  210.             if ( feld[i][j]!=0 )
  211.                 return 1;
  212.     return 0;
  213. }
  214.  
  215. /*
  216.     teste spielfeld ob steine entfernt werden können
  217.         entferne geg. steine
  218. */
  219. static int check_feld(uint *lines)
  220. {
  221. int flags[XHEIGHT][XWIDTH];
  222. int i,j;
  223. int ii;
  224. int done=0;
  225.  
  226.     memset(flags,0,sizeof(flags));
  227.     for ( i=FIRSTLINE; i<XHEIGHT-1; i++ ) {
  228.         for ( j=1; j<XWIDTH-1; j++ ) {
  229.             if ( feld[i][j]==0 )
  230.                 break;
  231.         }
  232.         if ( j==XWIDTH-1 ) {    /* kein break */
  233.             for ( j=1; j<XWIDTH-1; j++ ) {
  234.                 flags[i][j]=1;
  235.             }
  236.             (*lines)++;
  237.             done=1;
  238.         }
  239.     }
  240.  
  241.     if ( done ) {
  242. #if SOUND_LEVEL>0
  243.         do_sound(S_REMOVE);
  244. #endif
  245.  
  246.         for ( ii=8; ii<=tetris.last_flash; ii++ ) {
  247.             init_wait();
  248.             for ( i=FIRSTLINE; i<XHEIGHT-1; i++ ) {
  249.                 for ( j=1; j<XWIDTH-1; j++ ) {
  250.                     if ( flags[i][j] )
  251.                         tetris.dr_block(j,i,ii);
  252.                 }
  253.             }
  254.             copy_out();
  255.             do_wait(5);
  256.         }
  257.  
  258.         for ( j=1; j<XWIDTH-1; j++ ) {
  259.             for ( ii=i=XHEIGHT-2; ii>=FIRSTLINE; ii--,i-- ) {
  260.                 while ( flags[i][j]!=0 )
  261.                     i--;
  262.                 if ( i<0 )
  263.                     i=0;
  264.                 if ( i!=ii ) {
  265.                     feld[ii][j]=feld[i][j];
  266.                     tetris.dr_block(j,ii,feld[ii][j]);
  267.                 }
  268.             }
  269.         }
  270.         copy_out();
  271.     }
  272.     return done;
  273. }
  274.  
  275. /*
  276.     haupt-spielroutine
  277.         returns 0 -> abbruch, sonst score
  278. */
  279. uint do_tetris(void)
  280. {
  281. int key;
  282. long time;
  283. int draw,let_it_fall;
  284. STONE x;
  285. int i;
  286. uint level,delay;
  287. uint stones,lines,score;
  288. DIR *dir;
  289. uint stat[7]={0,0,0,0,0,0,0};
  290. int drop_line;
  291.  
  292.     init_feld();
  293.     check_feld(&lines);
  294.  
  295.     level=opts.opts[PM_TETRIS].start_level;
  296.     delay=calc_delay(level);
  297.     stones=lines=score=0;
  298.  
  299.     init_stone();
  300.  
  301.     while ( 1 ) {
  302.         stone=next;
  303.         init_stone();
  304. #if SOUND_LEVEL>1
  305.         do_sound(S_NEW);
  306. #endif
  307.         if ( preview_flag )
  308.             redraw_preview(0l);
  309.  
  310.         stat[stone.typ-1]++;
  311.         dr_stat(stat);
  312.  
  313.         if ( check_pos(&stone) || xcheck() )
  314.             break;                    /* stein checken */
  315.         x=stone;                    /* stein merken */
  316.  
  317.         stones++;
  318.         if ( level<9 && lines>level*10+10 )
  319.             { level++; inv_feld(); delay=calc_delay(level); }
  320.         dr_score(level,lines,stones,score);
  321.  
  322.         let_it_fall=0;                /* nicht fallen lassen */
  323.         time=gettime();                /* zeit merken */
  324.         draw=1;                        /* zeichnen */
  325.  
  326.         while ( 1 ) {
  327.             if ( draw ) {            /* nur wenn nötig */
  328.                 dr_stone();            /* stein zeichnen */
  329.                 draw=0;                /* flag löschen */
  330.                 copy_out();
  331.             }
  332.  
  333.             if ( !let_it_fall )        /* falls fallen lassen */
  334.                 key=get_key();
  335.             else
  336.                 key=0;                /* kein zeichen einlesen */
  337.  
  338.             switch ( key ) {
  339.               case K_QUIT:
  340.                 return 0;            /* beenden */
  341.               /*break;*/
  342.               case K_LEFT:
  343.                   x.x--;            /* links */
  344.                   if ( check_pos(&x) ) {
  345.                       x.x++;
  346. #if SOUND_LEVEL>3
  347.                     do_sound(S_CANT_LEFT);
  348.                 }
  349.                 else {
  350.                     do_sound(S_LEFT);
  351. #endif
  352.                 }
  353.               break;
  354.               case K_RIGHT:
  355.                 x.x++;                /* rechts */
  356.                   if ( check_pos(&x) ) {
  357.                       x.x--;
  358. #if SOUND_LEVEL>3
  359.                     do_sound(S_CANT_RIGHT);
  360.                 }
  361.                 else {
  362.                     do_sound(S_RIGHT);
  363. #endif
  364.                 }
  365.               break;
  366.               case K_ROTATE: {
  367.                int h=x.dir;
  368.                 x.dir++;
  369.                 if ( x.dir>=tet[x.typ].dirs )
  370.                     x.dir=0;
  371.                 if ( check_pos(&x) ) {
  372.                     x.dir=h;
  373. #if SOUND_LEVEL>3
  374.                     do_sound(S_CANT_ROTATE);
  375.                 }
  376.                 else {
  377.                     do_sound(S_ROTATE);
  378. #endif
  379.                 }
  380.               } break;
  381.               case K_ROT_CCW: {
  382.                int h=x.dir;
  383.                 x.dir--;
  384.                 if ( x.dir<0 )
  385.                     x.dir=tet[x.typ].dirs-1;
  386.                 if ( check_pos(&x) ) {
  387.                     x.dir=h;
  388. #if SOUND_LEVEL>3
  389.                     do_sound(S_CANT_ROT_CCW);
  390.                 }
  391.                 else {
  392.                     do_sound(S_ROT_CCW);
  393. #endif
  394.                 }
  395.               } break;
  396.               case K_DROP:
  397.                 let_it_fall=1;        /* fallen lassen */
  398.                 drop_line=stone.y;
  399. #if SOUND_LEVEL>2
  400.                     do_sound(S_DROP);
  401. #endif
  402.               break;
  403.               case K_LEVEL:
  404.                 if ( level<9 ) {
  405.                     level++;
  406.                     inv_feld();
  407.                     delay=calc_delay(level);
  408.                     dr_score(level,lines,stones,score);
  409.                 }
  410.               break;
  411.             }
  412.  
  413.             if ( gettime()>time+delay || (let_it_fall && gettime()>time+1) ) {
  414.                 x.y++;
  415.                 if ( check_pos(&x) )/* eins tiefer */
  416.                     { x.y--; break; }
  417. #if SOUND_LEVEL>2
  418.                 if ( let_it_fall )
  419.                     do_sound(S_DROPDOWN);
  420.                 else
  421.                     do_sound(S_STEPDOWN);
  422. #endif
  423.                 time=gettime();
  424.             }
  425.             if ( memcmp(&x,&stone,sizeof(x)) ) {
  426.                 draw=1;                /* falls sich was getan hat */
  427.                 rm_stone();            /* stein neuzeichnen */
  428.                 stone=x;
  429.             }
  430.         }
  431.  
  432. #if SOUND_LEVEL>1
  433.         do_sound(S_DOWN);
  434. #endif
  435.         if ( memcmp(&x,&stone,sizeof(x)) ) {
  436.             rm_stone();            /* stein neuzeichnen */
  437.             stone=x;
  438.             dr_stone();
  439.             copy_out();
  440.         }
  441.                                     /* stein ist unten angekommen */
  442.                                     /* eintragen ins feld */
  443.  
  444.         dir=&tet[stone.typ].dir[stone.dir];
  445.         for ( i=0; i<4; i++ )
  446.             feld[stone.y+dir->y[i]][stone.x+dir->x[i]]=stone.typ;
  447.  
  448.                                     /* steine wegräumen */
  449.         check_feld(&lines);
  450.  
  451.         score+=5+level*2;
  452.         if ( let_it_fall )
  453.             score+=XHEIGHT-1-drop_line;
  454.         else
  455.             score+=XHEIGHT-1-stone.y;
  456.         if ( preview_flag )
  457.             score-=3;
  458.  
  459.                                     /* tastaturpuffer löschen */
  460.         clr_keys();
  461.     }
  462.     dr_score(level,lines,stones,score);
  463.     return score;
  464. }
  465.  
  466.  
  467.